#include "Graphics.h"
#include <glad/glad.h>
#include "MathDefs.h"
#include "Shader.h"
#include "Context.h"

#define DEF_TO_INT(pointer, index)     (*((GLint*)(pointer) + index))
#define DEF_TO_FLOAT(pointer, index)   (*((GLfloat*)(pointer) + index))

Graphics::Graphics(Context* context):Object(context_)
{

}

Graphics::~Graphics()
{

}

void Graphics::SetUniform(bool isArray, GLuint location, unsigned int size, GLenum uniformType, void* data)
{
	GLsizei count = size;
	switch (uniformType)
	{
	case GL_INT:
	case GL_BOOL:
	case GL_SAMPLER_2D:
	case GL_SAMPLER_CUBE:
		if (isArray)
			glUniform1iv(location, count, (GLint*)data);
		else
			glUniform1i(location, DEF_TO_INT(data, 0));
		break;
	case GL_INT_VEC2:
	case GL_BOOL_VEC2:
		if (isArray)
			glUniform2iv(location, count, (GLint*)data);
		else
			glUniform2i(location, DEF_TO_INT(data, 0), DEF_TO_INT(data, 1));
		break;
	case GL_INT_VEC3:
	case GL_BOOL_VEC3:
		if (isArray)
			glUniform3iv(location, count, (GLint*)data);
		else
			glUniform3i(location,
				DEF_TO_INT(data, 0),
				DEF_TO_INT(data, 1),
				DEF_TO_INT(data, 2));
		break;
	case GL_INT_VEC4:
	case GL_BOOL_VEC4:
		if (isArray)
			glUniform4iv(location, count, (GLint*)data);
		else
			glUniform4i(location,
				DEF_TO_INT(data, 0),
				DEF_TO_INT(data, 1),
				DEF_TO_INT(data, 2),
				DEF_TO_INT(data, 4));
		break;
	case GL_FLOAT:
		if (isArray)
			glUniform1fv(location, count, (GLfloat*)data);
		else
			glUniform1f(location, DEF_TO_FLOAT(data, 0));
		break;
	case GL_FLOAT_VEC2:
		if (isArray)
			glUniform2fv(location, count, (GLfloat*)data);
		else
			glUniform2f(location, DEF_TO_FLOAT(data, 0), DEF_TO_FLOAT(data, 1));
		break;
	case GL_FLOAT_VEC3:
		if (isArray)
			glUniform3fv(location, count, (GLfloat*)data);
		else
			glUniform3f(location,
				DEF_TO_FLOAT(data, 0),
				DEF_TO_FLOAT(data, 1),
				DEF_TO_FLOAT(data, 2));
		break;
	case GL_FLOAT_VEC4:
		if (isArray)
			glUniform4fv(location, count, (GLfloat*)data);
		else
			glUniform4f(location,
				DEF_TO_FLOAT(data, 0),
				DEF_TO_FLOAT(data, 1),
				DEF_TO_FLOAT(data, 2),
				DEF_TO_FLOAT(data, 3));
		break;
	case GL_FLOAT_MAT2:
		glUniformMatrix2fv(location, count, GL_FALSE, (GLfloat*)data);
		break;
	case GL_FLOAT_MAT3:
		glUniformMatrix3fv(location, count, GL_FALSE, (GLfloat*)data);
		break;
	case GL_FLOAT_MAT4:
		glUniformMatrix4fv(location, count, GL_FALSE, (GLfloat*)data);
		break;
		break;

	default:
		assert(false);
		break;
	}
}

void Graphics::SetVBO(unsigned object)
{
	if (boundVBO_ != object)
	{
		if (object)
			glBindBuffer(GL_ARRAY_BUFFER, object);
		boundVBO_ = object;
	}
}

void Graphics::SetEBO(unsigned object)
{
	if (boundEBO_ != object)
	{
		if (object)
			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object);
		boundEBO_ = object;
	}
}


